const UTF8STRING = "utf8string";
const STRING = "string";
const INT = "int";
const LONG = "long";
const DOUBLE = "double";
const NULL = "null";
const SOLAR = "solar";
const LUNAR = "lunar";
const YES = "yes";
const NO = "no";

function DbParam(type, value) {
    this.type = type; // UTF8STRING, STRING, INT, LONG, DOUBLE, NULL
    this.value = value;
    
    this.toString = function() {
        return this.value + "(" + this.type + ")";        
    }
}

function Event() {
    this.id;
    this.day;
    this.month;
    this.year;
    this.type; // TYPES: SOLAR, LUNAR
    this.title;
    this.description;
    this.special; // SPECIALS: yes, no
    
    this.toString = function() {
        var text = "";
        text += this.id;
        text += "-{"
        text += this.day + "/" + this.month;
        text += "(" + this.type + ") ";
        text += this.title;
        text += (this.special)? "(*)" : "";
        text += (this.description)? (" - " + this.description) : "";
        text += "}";
        
        return text;
    }
}

function Storage(dbfile) {
    
    this.findEvents = function(solarDay, solarMonth, lunarDay, lunarMonth) {
        openDb();
                
        var sql = "SELECT * FROM events WHERE (day=?1 and month=?2 and type='solar') or (day=?3 and month=?4 and type='lunar')"
        var params = [new DbParam(INT, solarDay), new DbParam(INT, solarMonth), 
                      new DbParam(INT, lunarDay), new DbParam(INT, lunarMonth)];
        var statement = prepareStatement(sql, params);
        var events = new Array();
        while(statement.executeStep()) {
            var event = new Event();
            bindEvent(event, statement);            
            events.push(event);
        }
        
        closeDb(statement);
        
        return events;
    };
    
    this.findEventById = function(id) {
        openDb();
                
        var sql = "SELECT * FROM events WHERE id=?1"
        var params = [new DbParam(INT, id)];
        var statement = prepareStatement(sql, params);
        
        var event = null;
        if(statement.executeStep()) {
            event = new Event();
            bindEvent(event, statement);
        }
        
        closeDb(statement);
        
        return event;
    }
    
    this.insertEvent = function(event) {
        openDb();
                
        var sql = "INSERT INTO events(day, month, year, type, title, description, special) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"
        var params = [new DbParam(INT, event.day), new DbParam(INT, event.month), 
                      new DbParam(INT, event.year), new DbParam(STRING, event.type),
                      new DbParam(UTF8STRING, event.title), new DbParam(UTF8STRING, event.description),
                      new DbParam(STRING, event.special? "yes" : "no")];
                              
        var statement = prepareStatement(sql, params);
        statement.execute();
        statement.reset();    
        
        event.id = connection.lastInsertRowID;
        
        closeDb(statement);
    };
    
    this.modifyEvent = function(event) {
        openDb();
                
        var sql = "UPDATE events SET day=?1, month=?2, year=?3, type=?4, title=?5, description=?6, special=?7 WHERE id=?8"
        var params = [new DbParam(INT, event.day), new DbParam(INT, event.month), 
                      new DbParam(INT, event.year), new DbParam(STRING, event.type),
                      new DbParam(UTF8STRING, event.title), new DbParam(UTF8STRING, event.description),
                      new DbParam(STRING, event.special? "yes" : "no"), new DbParam(INT, event.id)];
                              
        var statement = prepareStatement(sql, params);
        statement.execute();
        statement.reset();    
        
        event.id = connection.lastInsertRowID;
        
        closeDb(statement);
    };
    
    this.deleteEvent = function(id) {
        openDb();
                
        var sql = "DELETE FROM events WHERE id=?1";
        var params = [new DbParam(INT, id)];
                              
        var statement = prepareStatement(sql, params);
        statement.execute();
        statement.reset();
        
        closeDb(statement);
    };
    
    this.getAllEvents = function() {
        openDb();
                
        var sql = "SELECT * FROM events ORDER BY month, day, type";
        var statement = prepareStatement(sql);
        var events = new Array();
        while(statement.executeStep()) {
            var event = new Event();
            bindEvent(event, statement);            
            events.push(event);
        }
        
        closeDb(statement);
        
        return events;
    }
    
    var connection;
    function openDb() {
        try {
            var storageService = getStorageService();
            connection = storageService.openDatabase(dbfile);
        } catch(e) {
            alert("Cannot init database!\n" + e.message);
        }
    }
    
    function prepareStatement(sql, params) {
        var statement = connection.createStatement(sql);
        if(params) {
            for(var i=0; i<params.length; i++) {
                if(params[i].value == undefined) {
                    statement.bindNullParameter(i);
                    continue;
                }
                switch(params[i].type) {
                    case UTF8STRING:
                        statement.bindUTF8StringParameter(i, params[i].value);
                        break;
                    case STRING:
                        statement.bindStringParameter(i, params[i].value);
                        break;
                    case INT:
                        statement.bindInt32Parameter(i, params[i].value);
                        break;
                    case LONG:
                        statement.bindInt64Parameter(i, params[i].value);
                        break;
                    case DOUBLE:
                        statement.bindDoubleParameter(i, params[i].value);
                        break;
                    case NULL:
                        statement.bindNullParameter(i);
                        break;
                }
            }
        }
        
        return statement;
    }
    
    function closeDb(statement) {
        try {
            statement.finalize();
            connection.close();
        } catch(e) {
            // do nothing
        }
    }
    
    function bindEvent(event, statement) {
        event.id = statement.getInt32(0);
        event.day = statement.getInt32(1);
        event.month = statement.getInt32(2);
        event.year = statement.getInt32(3);
        event.type = statement.getString(4);
        event.title = statement.getUTF8String(5);
        event.description = statement.getUTF8String(6);
        event.special = (statement.getString(7) == "yes");
    }
}